package org.third.security.cert;

import com.google.common.io.BaseEncoding;

import org.bouncycastle.x509.X509V2CRLGenerator;
import org.junit.Test;
import org.third.common.utils.HttpUtils;

import javax.security.auth.x500.X500Principal;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.X509CRL;
import java.security.cert.X509CRLEntry;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;

public class CrlTest {
	public static void main(String[] args) throws Exception {
		CrlTest crlTest = new CrlTest();
		crlTest.validateCrtWithCrl();
	}

	private String getCertificateThumbprint(String pfxPath, String password) {
		try {
			InputStream inStream = new FileInputStream(pfxPath);

			KeyStore ks = KeyStore.getInstance("PKCS12");
			ks.load(inStream, password.toCharArray());

			String alias = ks.aliases().nextElement();
			X509Certificate certificate = (X509Certificate) ks.getCertificate(alias);
			inStream.close();
			MessageDigest sha = MessageDigest.getInstance("SHA-1");
			return BaseEncoding.base16().encode(sha.digest(certificate.getEncoded()));
		} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException ex) {
			throw new RuntimeException(ex);
		}
	}

	public void getCrlFromLdapWithNoCaching() throws Exception {
		for (int i = 0; i < 10; i++) {
			CacheManager.getInstance().clearAll();
			final Cache cache = new Cache("crlCache-1", 100, false, false, 20, 10);
			CacheManager.getInstance().addCache(cache);
//			final CRLDistributionPointRevocationChecker checker = new CRLDistributionPointRevocationChecker(cache,
//					fetcher);
//			checker.setThrowOnFetchFailure(true);
//			checker.setUnavailableCRLPolicy(new AllowRevocationPolicy());
//			final X509Certificate cert = CertUtils.readCertificate(new ClassPathResource("ldap-crl.crt"));
//			checker.check(cert);
		}
	}

	@Test
	public void validateOcsp() throws Exception {
		
	
		KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
//		PKIXBuilderParameters xparams = new PKIXBuilderParameters(trustStore, new X509CertSelector());
//		Collection<? extends CRL> crls = getCRLs(crlf);
//		CertStoreParameters csp = new CollectionCertStoreParameters(crls);
//		CertStore store = CertStore.getInstance("Collection", csp);
//		xparams.addCertStore(store);
//		xparams.setRevocationEnabled(true); 
	}

	private void Crl(String CrlPath, String CASubject, String SigningKeyStore, String SigningKeyStorePWD, List Certlist,
			String CrlCircle) {

		try {

			PrivateKey CApriv = null;
			PublicKey CApubKey = null;
			PrivateKey AdminPriv = null;
			PublicKey AdminPubKey = null;
			X509Certificate caCert = null;
			KeyStore keystores = KeyStore.getInstance("jks");

			// String SigningKeyStore="D:\\workspace\\TestCA\\keystore\\CAKeystore";
			// String SigningKeyStorePWD="changeit";
			// String CASubject="CN=DemoCA,C=CN";

			InputStream input = new FileInputStream(SigningKeyStore);
			try {
				keystores.load(input, SigningKeyStorePWD.toCharArray());
			} catch (IOException e) {
			} finally {
				// IOUtils.closeQuietly(input);
			}
			Enumeration e1 = keystores.aliases();
			String name = "";
			if (e1 != null) {
				while (e1.hasMoreElements()) {
					String n = (String) e1.nextElement();
					if (keystores.isKeyEntry(n)) {
						name = n;
					}
				}
			}
			CApriv = (PrivateKey) keystores.getKey(CASubject, SigningKeyStorePWD.toCharArray());
			caCert = (X509Certificate) keystores.getCertificate(CASubject);

			X509V2CRLGenerator x509V2CrlGenerator = new X509V2CRLGenerator();
			Date dt = new Date();
			Date notAfter = new Date(dt.getTime() + Integer.parseInt(CrlCircle) * 60 * 1000L);
			X500Principal issuer = new X500Principal(CASubject);
			// CRLGen.setIssuerDN(issuer);
			x509V2CrlGenerator.setThisUpdate(dt);
			x509V2CrlGenerator.setNextUpdate(notAfter);
			x509V2CrlGenerator.setSignatureAlgorithm("SHA1withRSA");

			// X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(issuer.g);

			for (int i = 0; i < Certlist.size(); i++) {
				try {
					// CERTSN,DATE,REASON
					String tmp[] = Certlist.get(i).toString().split("\\,");

					String ss = tmp[0].toUpperCase().toString();
					System.out.println(">>>>>>" + ss);
					BigInteger certSN = new BigInteger(ss, 16);
					System.out.println(certSN.toString());
					SimpleDateFormat myFormatter = new SimpleDateFormat("yyyyMMddHHmmSSSSS");
					System.out.println(ss.toString());
					Date RevokeDT = myFormatter.parse(tmp[1].toString());

					int r = Integer.parseInt(tmp[2].toString());

					x509V2CrlGenerator.addCRLEntry(certSN, RevokeDT, r);

				} catch (Exception e) {

				}
			}

			String Crlbase64 = new String(
					Base64.getEncoder().encodeToString(x509V2CrlGenerator.generateX509CRL(CApriv).getEncoded()));
			// System.out.println();

			try {
				FileWriter fw = new FileWriter(new File(CrlPath));
				fw.write(Crlbase64);
				fw.close();
			} catch (Exception e) {
				e.printStackTrace();
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	private void validateCrtWithCrl() throws Exception {
		String packagePath = CrlTest.class.getResource(".").getFile();
		System.out.println(packagePath);

		// 创建CRL对象
		String crlPath = packagePath + "client.crl";
		X509CRL crl = parseCrlFile(crlPath);

		// 创建包含可用和被吊销的两个证书对象的数组
		String availCertPath = packagePath + "wanghongjun.cer";
		String unAvailCertPath = packagePath + "liuheng.cer";
		X509Certificate[] certArray = new X509Certificate[2];
		certArray[0] = getCertificate(availCertPath);
		certArray[1] = getCertificate(unAvailCertPath);

		// 验证证书是否被吊销
		for (int i = 0; i < certArray.length; i++) {
			System.out.println("证书序列号=" + getSerialNumber(certArray[i]));
			System.out.println("证书DN=" + certArray[i].getSubjectDN());
			if (crl.isRevoked(certArray[i])) {
				System.out.println("证书被吊销\n");
			} else {
				System.out.println("证书可用\n");
			}
		}
	}

	public X509CRL parseCrlFile(String crlFile) throws Exception {
		// openssl ca -gencrl -out xxx.crl -keyfile /opt/kubernetes/ssl/ca.key -cert
		// /opt/kubernetes/ssl/ca.crt

		FileInputStream fis = new FileInputStream(crlFile);
		CertificateFactory cf = CertificateFactory.getInstance("X.509");
		X509CRL crl = (X509CRL) cf.generateCRL(fis);
		System.out.println(crl.getIssuerDN());

		int i = 0;
		Set tSet = crl.getRevokedCertificates();
		Iterator tIterator = tSet.iterator();

		// System.out.println("tIterator "+tIterator);

		while (tIterator.hasNext()) {
			X509CRLEntry tEntry = (X509CRLEntry) tIterator.next();
			String sn = tEntry.getSerialNumber().toString(16).toUpperCase();
			String issName = crl.getIssuerDN().toString();
			String time = new SimpleDateFormat("yyyyMMddHHmmss").format(tEntry.getRevocationDate());
			i++;
			System.out.println(sn);
			System.out.println(issName);
			System.out.println(time);
			System.out.println("***************************");
		}
		fis.close();
		return crl;
	}

	public static X509Certificate getCertificate(String certFilePath) throws Exception {
		FileInputStream in = new FileInputStream(certFilePath);
		CertificateFactory cf = CertificateFactory.getInstance("X.509");
		X509Certificate cert = (X509Certificate) cf.generateCertificate(in);
		return cert;
	}

	/**
	 * 读取证书序列号
	 * 
	 * @param cert
	 * @return
	 */
	public static String getSerialNumber(X509Certificate cert) {
		if (null == cert)
			return null;
		byte[] serial = cert.getSerialNumber().toByteArray();
		if (serial.length > 0) {
			String serialNumberString = new String();
			for (int i = 0; i < serial.length; i++) {
				String s = Integer.toHexString(Byte.valueOf(serial[i]).intValue());
				if (s.length() == 8)
					s = s.substring(6);
				else if (1 == s.length())
					s = "0" + s;
				serialNumberString += s + " ";
			}
			return serialNumberString;
		}
		return null;
	}
}
